import tkinter as tk
from tkinter import ttk, messagebox
import socket
import threading
import time

class SocketDemo:
    def __init__(self, root):
        self.root = root
        self.root.title("Socket通信演示")
        self.root.geometry("800x600")
        
        # 服务器和客户端状态
        self.server_status = "未启动"
        self.client_status = "未连接"
        self.server_message = ""
        self.client_message = ""
        self.input_text = tk.StringVar(value="Hello, World!")
        
        # 创建界面
        self.create_widgets()
        
        # Socket对象
        self.server_socket = None
        self.client_socket = None
        
    def create_widgets(self):
        # 标题
        title_label = ttk.Label(self.root, text="Socket通信演示 - 客户端服务器模型", 
                               font=("Arial", 16, "bold"))
        title_label.pack(pady=10)
        
        # 说明文本
        instructions = [
            "这是一个简单的Socket通信演示",
            "1. 点击'启动服务器'按钮启动服务器",
            "2. 点击'连接服务器'建立客户端连接",
            "3. 在服务器输入框输入消息",
            "4. 点击'发送消息'将消息发送到客户端"
        ]
        
        for instruction in instructions:
            label = ttk.Label(self.root, text=instruction)
            label.pack()
        
        # 创建主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(pady=20, fill=tk.BOTH, expand=True)
        
        # 服务器框架
        server_frame = ttk.LabelFrame(main_frame, text="服务器", padding=10)
        server_frame.pack(side=tk.LEFT, padx=10, fill=tk.BOTH, expand=True)
        
        # 服务器状态
        ttk.Label(server_frame, text="状态:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.server_status_label = ttk.Label(server_frame, text=self.server_status, foreground="red")
        self.server_status_label.grid(row=0, column=1, sticky=tk.W, pady=5)
        
        # 启动服务器按钮
        self.start_server_btn = ttk.Button(server_frame, text="启动服务器", command=self.start_server)
        self.start_server_btn.grid(row=1, column=0, columnspan=2, pady=10)
        
        # 服务器消息输入
        ttk.Label(server_frame, text="发送的消息:").grid(row=2, column=0, columnspan=2, sticky=tk.W, pady=(20,5))
        self.server_msg_entry = ttk.Entry(server_frame, textvariable=self.input_text, width=30)
        self.server_msg_entry.grid(row=3, column=0, columnspan=2, pady=5, padx=5, sticky=tk.EW)
        
        # 发送消息按钮
        self.send_msg_btn = ttk.Button(server_frame, text="发送消息", command=self.send_message, state=tk.DISABLED)
        self.send_msg_btn.grid(row=4, column=0, columnspan=2, pady=10)
        
        # 客户端框架
        client_frame = ttk.LabelFrame(main_frame, text="客户端", padding=10)
        client_frame.pack(side=tk.RIGHT, padx=10, fill=tk.BOTH, expand=True)
        
        # 客户端状态
        ttk.Label(client_frame, text="状态:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.client_status_label = ttk.Label(client_frame, text=self.client_status, foreground="red")
        self.client_status_label.grid(row=0, column=1, sticky=tk.W, pady=5)
        
        # 连接服务器按钮
        self.connect_btn = ttk.Button(client_frame, text="连接服务器", command=self.connect_to_server)
        self.connect_btn.grid(row=1, column=0, columnspan=2, pady=10)
        
        # 客户端接收消息
        ttk.Label(client_frame, text="接收的消息:").grid(row=2, column=0, columnspan=2, sticky=tk.W, pady=(20,5))
        self.client_msg_label = ttk.Label(client_frame, text="", background="white", relief=tk.SUNKEN, width=30)
        self.client_msg_label.grid(row=3, column=0, columnspan=2, pady=5, padx=5, sticky=tk.EW)
        
        # 连接可视化
        self.connection_canvas = tk.Canvas(self.root, height=100, bg="white")
        self.connection_canvas.pack(fill=tk.X, padx=20, pady=10)
        
        # 绘制初始连接线
        self.draw_connection()
        
    def draw_connection(self):
        self.connection_canvas.delete("all")
        width = self.connection_canvas.winfo_width()
        if width < 2:
            width = 800
            
        center_y = 50
        
        # 绘制服务器和客户端图标
        self.connection_canvas.create_oval(50, center_y-20, 90, center_y+20, fill="lightblue", outline="darkblue")
        self.connection_canvas.create_text(70, center_y, text="S", font=("Arial", 14, "bold"))
        
        self.connection_canvas.create_oval(width-90, center_y-20, width-50, center_y+20, fill="lightgreen", outline="darkgreen")
        self.connection_canvas.create_text(width-70, center_y, text="C", font=("Arial", 14, "bold"))
        
        # 绘制连接线
        if self.client_status == "已连接":
            line_color = "green"
            self.connection_canvas.create_line(90, center_y, width-90, center_y, fill=line_color, width=3, arrow=tk.BOTH)
            
            # 绘制数据传输动画
            if hasattr(self, 'message_animation') and self.message_animation:
                x = getattr(self, 'anim_pos', 100)
                self.connection_canvas.create_oval(x-5, center_y-5, x+5, center_y+5, fill="blue")
                
                # 更新动画位置
                if x < width-100:
                    self.anim_pos = x + 5
                else:
                    self.anim_pos = 100
                    
                self.root.after(50, self.draw_connection)
        else:
            line_color = "red"
            self.connection_canvas.create_line(90, center_y, width-90, center_y, fill=line_color, width=3, dash=(4,2))
        
    def start_server(self):
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.bind(('localhost', 12345))
            self.server_socket.listen(1)
            self.server_status = "运行中，等待连接..."
            self.server_status_label.config(text=self.server_status, foreground="green")
            self.start_server_btn.config(state=tk.DISABLED)
            
            # 启动服务器线程
            server_thread = threading.Thread(target=self.accept_connections)
            server_thread.daemon = True
            server_thread.start()
            
        except Exception as e:
            messagebox.showerror("错误", f"启动服务器失败: {str(e)}")
            
    def accept_connections(self):
        try:
            self.conn, self.addr = self.server_socket.accept()
            self.server_status = f"已连接: {self.addr}"
            self.server_status_label.config(text=self.server_status, foreground="blue")
            self.send_msg_btn.config(state=tk.NORMAL)
        except:
            pass  # 服务器关闭时会产生异常
            
    def connect_to_server(self):
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client_socket.connect(('localhost', 12345))
            self.client_status = "已连接"
            self.client_status_label.config(text=self.client_status, foreground="green")
            self.connect_btn.config(state=tk.DISABLED)
            
            # 启动客户端接收线程
            client_thread = threading.Thread(target=self.receive_messages)
            client_thread.daemon = True
            client_thread.start()
            
            # 更新连接可视化
            self.draw_connection()
            
        except Exception as e:
            messagebox.showerror("错误", f"连接服务器失败: {str(e)}")
            
    def send_message(self):
        if hasattr(self, 'conn'):
            try:
                message = self.input_text.get()
                self.conn.send(message.encode('utf-8'))
                self.server_message = message
                
                # 启动消息动画
                self.message_animation = True
                self.anim_pos = 100
                self.draw_connection()
                
            except Exception as e:
                messagebox.showerror("错误", f"发送消息失败: {str(e)}")
                
    def receive_messages(self):
        while True:
            try:
                message = self.client_socket.recv(1024).decode('utf-8')
                if message:
                    self.client_message = message
                    self.client_msg_label.config(text=self.client_message)
                    
                    # 停止消息动画
                    self.message_animation = False
                    self.draw_connection()
                    
            except:
                break  # 连接关闭时退出循环
                
    def __del__(self):
        # 清理资源
        if hasattr(self, 'server_socket') and self.server_socket:
            self.server_socket.close()
        if hasattr(self, 'client_socket') and self.client_socket:
            self.client_socket.close()

if __name__ == "__main__":
    root = tk.Tk()
    app = SocketDemo(root)
    root.mainloop()